/***************************************************************************************

***************************************************************************************/
/*!
*************************************************************************************
* \file biaridecod.c
*
* \brief
*    binary arithmetic decoder routines
* \date
*   
* \author
*    Main contributors (see contributors.h for copyright, address and affiliation details)
*************************************************************************************
*/

#include <stdlib.h>
#include "math.h"
#include "global.h"
#include "memalloc.h"
#include <assert.h>



//AC ENGINE PARAMETERS
unsigned int s1,t1,value_s,value_t;
unsigned char dec_bypass,dec_final;

extern int symbolCount;

extern BbvBuffer_t *pBbv;  

int binCount = 0;

#define Dbuffer         (dep->Dbuffer)
#define Dbits_to_go     (dep->Dbits_to_go)
#define Dcodestrm       (dep->Dcodestrm)
#define Dcodestrm_len   (dep->Dcodestrm_len)

#define B_BITS	10

#define LG_PMPS_SHIFTNO 2

#define HALF      (1 << (B_BITS-1))
#define QUARTER   (1 << (B_BITS-2))


/************************************************************************
* M a c r o s
************************************************************************
*/


#define get_byte(){                                         \
  Dbuffer = Dcodestrm[(*Dcodestrm_len)++];\
  Dbits_to_go = 7;                        \
  \
  if (input->check_BBV_flag && pBbv)      \
{                                       \
  pBbv->frame_code_bits += 8;           \
}                                       \
}



/************************************************************************
************************************************************************
init / exit decoder
************************************************************************
************************************************************************/


/*!
************************************************************************
* \brief
*    Allocates memory for the DecodingEnvironment struct
* \return DecodingContextPtr
*    allocates memory
************************************************************************
*/
DecodingEnvironmentPtr arideco_create_decoding_environment()
{
  DecodingEnvironmentPtr dep;

  if ((dep = calloc(1,sizeof(DecodingEnvironment))) == NULL)
    no_mem_exit("arideco_create_decoding_environment: dep");
  return dep;
}


/*!
***********************************************************************
* \brief
*    Frees memory of the DecodingEnvironment struct
***********************************************************************
*/
void arideco_delete_decoding_environment(DecodingEnvironmentPtr dep)
{
  if (dep == NULL)
  {
    snprintf(errortext, ET_SIZE, "Error freeing dep (NULL pointer)");
    error (errortext, 200);
  }
  else
    free(dep);
}


/*!
************************************************************************
* \brief
*    Initializes the DecodingEnvironment for the arithmetic coder
************************************************************************
*/


void arideco_start_decoding(DecodingEnvironmentPtr dep, unsigned char *cpixcode,
                            int firstbyte, int *cpixcode_len )
{

  Dcodestrm = cpixcode;
  Dcodestrm_len = cpixcode_len;
  *Dcodestrm_len = firstbyte;

  s1 = 0;
  t1 = QUARTER-1;//0xff
  value_s = 0;

  value_t = 0;

  {
    int i;
    Dbits_to_go = 0;
    for (i = 0; i < B_BITS -1 ; i++) 
    {
      if (--Dbits_to_go < 0)
        get_byte();
      value_t = (value_t<<1)  | ((Dbuffer >> Dbits_to_go) & 0x01); 
    }
  }

  while (value_t<QUARTER){
    if (--Dbits_to_go < 0) 
      get_byte();   
    // Shift in next bit and add to value 
    value_t = (value_t << 1) | ((Dbuffer >> Dbits_to_go) & 0x01);
    value_s++;
  }
  value_t = value_t & 0xff;

  dec_final = dec_bypass  = 0;		
}



/*!
************************************************************************
* \brief
*    arideco_bits_read
************************************************************************
*/
int arideco_bits_read(DecodingEnvironmentPtr dep)
{
  return 8 * ((*Dcodestrm_len)-1) + (8 - Dbits_to_go);
}


/*!
************************************************************************
* \brief
*    arideco_done_decoding():
************************************************************************
*/
void arideco_done_decoding(DecodingEnvironmentPtr dep)
{
  if (Dbits_to_go!=8)
  {

    currStream->read_len --; 
    //arienc_start_encoding 
    currStream->frame_bitoffset += (currStream->read_len) *8;  //multiple slice
    Dbits_to_go = 8;
  }
  else
  {
    currStream->read_len -=2;
    currStream->frame_bitoffset += (currStream->read_len) *8;  //multiple slice

  }
}

unsigned int biari_decode_symbol(DecodingEnvironmentPtr dep, BiContextTypePtr bi_ct )
{
  register unsigned char bit ;
  register unsigned char s_flag,is_LPS=0;
  register unsigned char cwr,cycno=bi_ct->cycno;
  register unsigned int lg_pmps= bi_ct->LG_PMPS;
  register unsigned int t_rlps;
  register unsigned int s2,t2;


  bit = bi_ct->MPS;

  cwr = (cycno<=1)?3:(cycno==2)?4:5;//FAST ADAPTION PARAMETER


  if (t1>=(lg_pmps>>LG_PMPS_SHIFTNO))
  {
    s2 = s1;
    t2 = t1 - (lg_pmps>>LG_PMPS_SHIFTNO);//8bits
    s_flag = 0;
  }
  else
  {
    s2 = s1+1;
    t2 = 256 + t1 - (lg_pmps>>LG_PMPS_SHIFTNO);//8bits
    s_flag = 1;
  }


  if(s2>value_s||(s2==value_s&&value_t>=t2))//LPS
  {
    is_LPS = 1;
    bit=!bit;//LPS
    //if (dec_final)  return(bit);  //multiple slice

    t_rlps = (s_flag==0)? (lg_pmps>>LG_PMPS_SHIFTNO)
      :(t1 + (lg_pmps>>LG_PMPS_SHIFTNO));		

    if (s2==value_s)
      value_t = (value_t-t2);
    else
    {
      if (--Dbits_to_go < 0) 
        get_byte();   
      // Shift in next bit and add to value 
      value_t = (value_t << 1) | ((Dbuffer >> Dbits_to_go) & 0x01);
      value_t = 256 + value_t - t2;
    }

    //restore range		
    while (t_rlps<QUARTER){
      t_rlps=t_rlps<<1;
      if (--Dbits_to_go < 0) 
        get_byte();   
      // Shift in next bit and add to value 
      value_t = (value_t << 1) | ((Dbuffer >> Dbits_to_go) & 0x01);
    }

    s1 = 0;
    t1 = t_rlps & 0xff;

    //restore value
    value_s = 0;
    while (value_t<QUARTER){
      int j;
      if (--Dbits_to_go < 0) 
        get_byte();   
      j=(Dbuffer >> Dbits_to_go) & 0x01;
      // Shift in next bit and add to value 

      value_t = (value_t << 1) | j;
      value_s++;
    }
    value_t = value_t & 0xff;		
  }
  else //MPS
  {		
    //if (dec_final)  return(bit);	  //multiple slice
    s1 = s2;
    t1 = t2;				
  }

  if (dec_bypass) return(bit);

  //update other parameters
  if (is_LPS)
    cycno=(cycno<=2)?(cycno+1):3;
  else if (cycno==0) 
    cycno =1;			
  bi_ct->cycno=cycno;

  //update probability estimation
  if (is_LPS)
  {	
    switch(cwr) {
    case 3:	lg_pmps = lg_pmps + 197;					
      break;
    case 4: lg_pmps = lg_pmps + 95;
      break;
    default:lg_pmps = lg_pmps + 46; 
    }

    if (lg_pmps>=(256<<LG_PMPS_SHIFTNO))
    {
      lg_pmps = (512<<LG_PMPS_SHIFTNO) - 1 - lg_pmps;
      bi_ct->MPS = !(bi_ct->MPS);
    }	
  }
  else
  {
    lg_pmps = lg_pmps - (unsigned int)(lg_pmps>>cwr) - (unsigned int)(lg_pmps>>(cwr+2));	
  }	

  bi_ct->LG_PMPS = lg_pmps;

  return(bit);
}

unsigned int biari_decode_symbolW(DecodingEnvironmentPtr dep, BiContextTypePtr bi_ct1 ,BiContextTypePtr bi_ct2 )
{
  register unsigned char bit1,bit2; 
  register unsigned char pred_MPS,bit;
  register unsigned int  lg_pmps;
  register unsigned char cwr1,cycno1=bi_ct1->cycno;
  register unsigned char cwr2,cycno2=bi_ct2->cycno;
  register unsigned int lg_pmps1= bi_ct1->LG_PMPS,lg_pmps2= bi_ct2->LG_PMPS;
  register unsigned int t_rlps;
  register unsigned char s_flag,is_LPS=0;
  register unsigned int s2,t2;

  bit1 = bi_ct1->MPS;
  bit2 = bi_ct2->MPS;


  cwr1 = (cycno1<=1)?3:(cycno1==2)?4:5;
  cwr2 = (cycno2<=1)?3:(cycno2==2)?4:5; 

  if (bit1 == bit2) 
  {
    pred_MPS = bit1;
    lg_pmps = (lg_pmps1 + lg_pmps2)/2;
  }
  else 
  {
    if (lg_pmps1<lg_pmps2) {
      pred_MPS = bit1;
      lg_pmps = (256<<LG_PMPS_SHIFTNO) - 1 - ((lg_pmps2 - lg_pmps1)>>1);
    }
    else {
      pred_MPS = bit2;
      lg_pmps = (256<<LG_PMPS_SHIFTNO) - 1 - ((lg_pmps1 - lg_pmps2)>>1);
    }
  }

  if (t1>=(lg_pmps>>LG_PMPS_SHIFTNO))
  {
    s2 = s1;
    t2 = t1 - (lg_pmps>>LG_PMPS_SHIFTNO);
    s_flag = 0;
  }
  else
  {
    s2 = s1+1;
    t2 = 256+t1 - (lg_pmps>>LG_PMPS_SHIFTNO);
    s_flag = 1;
  }

  bit = pred_MPS;
  if(s2>value_s||(s2==value_s&&value_t>=t2))//LPS
  {			
    is_LPS = 1;
    bit=!bit;//LPS
    t_rlps = (s_flag==0)? (lg_pmps>>LG_PMPS_SHIFTNO):(t1 + (lg_pmps>>LG_PMPS_SHIFTNO));		

    if (s2==value_s)
      value_t = (value_t-t2);
    else
    {		
      if (--Dbits_to_go < 0) 
        get_byte();   
      // Shift in next bit and add to value 
      value_t = (value_t << 1) | ((Dbuffer >> Dbits_to_go) & 0x01);
      value_t = 256 + value_t-t2;
    }

    //restore range		
    while (t_rlps<QUARTER){
      t_rlps=t_rlps<<1;
      if (--Dbits_to_go < 0) 
        get_byte();   
      // Shift in next bit and add to value 
      value_t = (value_t << 1) | ((Dbuffer >> Dbits_to_go) & 0x01);
    }
    s1 = 0;
    t1 = t_rlps & 0xff;

    //restore value
    value_s = 0;
    while (value_t<QUARTER){
      int j;
      if (--Dbits_to_go < 0) 
        get_byte();   
      j=(Dbuffer >> Dbits_to_go) & 0x01;
      // Shift in next bit and add to value 

      value_t = (value_t << 1) | j;
      value_s++;
    }
    value_t = value_t & 0xff;			
  }//--LPS 
  else //MPS
  {
    s1 = s2;
    t1 = t2;
  }

  if (bit!=bit1)
  {			
    cycno1 = (cycno1<=2)?(cycno1+1):3;//LPS occurs
  }
  else{
    if (cycno1==0) cycno1 =1;
  }

  if (bit !=bit2)
  {			
    cycno2 = (cycno2<=2)?(cycno2+1):3;//LPS occurs
  }
  else
  {
    if (cycno2==0) cycno2 =1;
  }
  bi_ct1->cycno = cycno1;
  bi_ct2->cycno = cycno2;

  //update probability estimation
  {
    //bi_ct1
    if (bit==bit1)
    {
      lg_pmps1 = lg_pmps1 - (unsigned int)(lg_pmps1>>cwr1) - (unsigned int)(lg_pmps1>>(cwr1+2));	
    }
    else
    {
      switch(cwr1) {
      case 3:	lg_pmps1 = lg_pmps1 + 197;					
        break;
      case 4: lg_pmps1 = lg_pmps1 + 95;
        break;
      default:lg_pmps1 = lg_pmps1 + 46; 
      }

      if (lg_pmps1>=(256<<LG_PMPS_SHIFTNO))
      {
        lg_pmps1 = (512<<LG_PMPS_SHIFTNO) - 1 - lg_pmps1;
        bi_ct1->MPS = !(bi_ct1->MPS);
      }	
    }
    bi_ct1->LG_PMPS = lg_pmps1;

    //bi_ct2
    if (bit==bit2)
    {
      lg_pmps2 = lg_pmps2 - (unsigned int)(lg_pmps2>>cwr2) - (unsigned int)(lg_pmps2>>(cwr2+2));	
    }
    else
    {
      switch(cwr2) {
      case 3:	lg_pmps2 = lg_pmps2 + 197;					
        break;
      case 4: lg_pmps2 = lg_pmps2 + 95;
        break;
      default:lg_pmps2 = lg_pmps2 + 46; 
      }

      if (lg_pmps2>=(256<<LG_PMPS_SHIFTNO))
      {
        lg_pmps2 = (512<<LG_PMPS_SHIFTNO) - 1 - lg_pmps2;
        bi_ct2->MPS = !(bi_ct2->MPS);
      }	
    }
    bi_ct2->LG_PMPS = lg_pmps2;
  }

  return(bit);
}


/*!
************************************************************************
* \brief
*    biari_decode_symbol_eq_prob():
* \return
*    the decoded symbol
************************************************************************
*/
unsigned int biari_decode_symbol_eq_prob(DecodingEnvironmentPtr dep)
{
  unsigned int bit;
  BiContextType octx;
  BiContextTypePtr ctx=&octx;
  ctx->LG_PMPS = (QUARTER<<LG_PMPS_SHIFTNO)-1;
  ctx->MPS = 0;
  dec_bypass = 1;
  bit = biari_decode_symbol(dep,ctx);
  dec_bypass = 0;
  return(bit);
}

unsigned int biari_decode_final(DecodingEnvironmentPtr dep)
{	
  unsigned int bit;
  BiContextType octx;
  BiContextTypePtr ctx=&octx;
  ctx->LG_PMPS = 1<<LG_PMPS_SHIFTNO;
  ctx->MPS = 0;
  dec_final = 1;
  bit = biari_decode_symbol(dep,ctx);
  dec_final = 0;
  return(bit);
}

void biari_init_context_logac (BiContextTypePtr ctx)
{
  ctx->LG_PMPS = (QUARTER<<LG_PMPS_SHIFTNO)-1; //10 bits precision
  ctx->MPS	 = 0;	
  ctx->cycno  =  0;
}






















